local handler = require "handler"
local util = require "util"
local reason = require "reason"
local error_code = require "error_code"
local constant = require "constant"
local cocall = require "cocall"
local game_def = require "game_def"
local cjson = require "cjson"
local skynet = require("skynet")
local server_config = dofile(skynet.getenv("server_config"))
local utils = require("utils")

local table_insert = table.insert
local table_sort = table.sort
local math_floor = math.floor
local notify_money_changed = handler.notify_money_changed
local add_awards = handler.add_awards
local tostring = tostring

--[[
K T, [08.04.20 11:12]
game_code 父游戏id,自己用的
platform 三方平台BG、AG
type_code 三方游戏类型,1001:电子，1002:视讯，1003:体育 1004:电竞 
table_code 三方游戏code
game_name 游戏名称
K T, [08.04.20 11:13]
platform 三方平台BG、AG
type_code 三方游戏类型,1001:电子，1002:视讯，1003:体育 1004:电竞 
table_code 三方游戏code

sky
服务器需要对转入转出做加币操作
1，skynet服务器跟go视讯服务器连接不上，需要将玩家之前扣除货币加上（主要是golang服务器出bug短暂重启，超时不算）
2,   golang在未调用转入视讯额度之前给skynet返回的错误 均需要将玩家之前扣除货币加上（这种情况出现甚少，大部分是skynet跟golang预定的参数有问题）
3,   视讯转入额度接口返回失败情况skynet均需要给玩家之前扣除货币加上 (这种是视讯返回的失败)
4，其他错误情况均不给用户加回金币，均通过打印billlog给PHP，PHP在后台进行显示具体失败的原因，并且提供给运营可以手动回调的操作（一般到这种出错主要原因大部分是视讯接口超时）

billlog打印规则
1， 如果是正常成功转入，打日志告诉php转入成功，php后台进行展示（成功不需要显示回调按钮）
2,   如果是以上(1到3)三种情况的错误，打印日志告诉php转入失败并且提示金币已返回到用户账号中 （这种情况不需要显示回调按钮）
3， 如果是第4种情况，那么打印日志告诉php转入失败，并且后台展示具体失败原因，并且提供手动回调按钮，当运营点击手动回调成功后需要隐藏掉手动回调按钮
--]]



local shisun_config = nil --视讯配置
local game_list = {} --游戏列表
local can_get_shisun = true --防刷
local can_set_shisun = true --防刷
local in_shisun_game = false --不在视讯中


local shisun_handler = {
    
}

--取错误码的内容
local function getErrResult(err_code, num)
    local function get_code_des(err_code)
        return global_configs.error_des[err_code]
    end  
    local ok, des = xpcall(get_code_des, debug.traceback, err_code)
    if not ok then 
        errlog("错误码配置有问题", err_code)
        des = "错误码配置有问题"
        if err_code then 
            des = string.format("错误码配置有问题%d", err_code)
        end
    end
    if num then 
        des = string.format(des, num)
    end
    return { result = err_code, description=des }
end

--通过game_type取配置
local function getShisunConf(game_type)
    if not next(game_list) then 
        local channel = player.channel
        local os_system = player.os_system
        local game_menu = global_configs.game_list[channel] or {}
        game_menu = game_menu[os_system] or game_menu['all']
        if not game_menu then
            game_menu = global_configs.game_list['guanwang'] or {}
            game_menu = game_menu[os_system] or game_menu['all'] or {}
        end
        game_list = game_menu.game_list or {}
    end    
    print("____getShisunConf____", player.uid, game_type)
    for k, v in pairs(game_list) do 
        if v.game_type == game_type then 
            return v
        end
    end
    errlog("____getShisunConf____", player.uid, game_type)
end

--玩家是否已经在桌子上了
local function isInTableSvr(uid)
    local ok, table_gid = R().exdbsvr(1):call('.tlock_mgr','get_player_table',uid)
    if not ok then
        errlog(uid,'REQ_ENTER_SHISUN failed to get_player_table')
        send_to_gateway('shisun.RSP_ENTER_SHISUN', {result = error_code.REMOTE_CALL_FAIL}) 
        return false
    end
    if table_gid ~= 0 then
        print("____222___REQ_ENTER_SHISUN_________")
        local tsvr_id = utils.extract_table_gid(table_gid)
        local dest = R().tablesvr(tsvr_id):dest()
        local curr_game_type = 0
        local curr_table_type = 0
        if table_gid and table_gid > 0 then
            local ok,succ,ret_game_type,ret_table_type = R().dest(dest):call('.table_mgr','get_game_type',table_gid)
            if not ok then
                errlog(uid,'failed to get game type',table_gid,ret_game_type,ret_table_type)
                table_gid = 0
                dest = 0
            else
                curr_game_type = ret_game_type or 0
                curr_table_type = ret_table_type or 0
            end
        end
        if curr_table_type > 0 then
            send_to_gateway('shisun.NTF_SELF_ONTABLE',{
                dest = dest,
                table_gid = table_gid,
                game_type = curr_game_type,
            })            
            send_to_gateway('shisun.RSP_ENTER_SHISUN', {result = error_code.REMOTE_CALL_FAIL})            
            return false
        end
        errlog("_____REQ_ENTER_SHISUN___被锁在桌子里了______")
        send_to_gateway('shisun.RSP_ENTER_SHISUN', {result = error_code.REMOTE_CALL_FAIL})
        return false
    end

    return true
end


--发送消息给mongo
local function call_mongo(collection, cmd, ...)
    local res = skynet.call(".mongo", "lua", "mongo_cmd", collection, cmd, ...)
    return res
end

local function send_mongo(collection, cmd, ...)
    skynet.send(".mongo", "lua", "mongo_cmd", collection, cmd, ...)   
end

--生成定单号
local function call_order_id(uid)
    return skynet.call(".order_id", "lua", "get_order_id", uid)   
end




--操作失败加回金币
local function back_coin(coins)
    local user_data = player.user_data
    local uid = player.uid
    local reason = reason.SET_SHISUN_COIN_EER
    local billInfo =  {
        table_type = shisun_config.game_type,
        game_type = shisun_config.game_code,
        client_version = player.client_version,
        channel = player.channel,
        cur_channel = player.cur_channel,
        device_id = player.device_id,
        device_brand = player.device_brand,        
    }        
    local ok, succ, ret = R().basesvr({key=uid}):call('.msg_handler', 'add_coins', uid, coins, reason, billInfo)
    if not ok or not succ then
        errlog(uid,'操作金币失败failed to add coins', ok, succ, coins, reason)        
        return false
    end  
    player.coins = ret.curr
    notify_money_changed(uid,{
        coins = player.coins,
    })
    return true
end

local function send_billog(platform, uid, coins, order_type, err_code, err_msg, order_id, status)
    --订单号order_id

    --给后台发billog
    local data = {            
        uid = uid,
        orderid = order_id,
        amount = coins or 0,
        type = order_type, --类型转入视讯1，转出视讯2
        error_code = err_code,
        msg = err_msg or "",
        third_platform = platform,
        status = status, --1成功，2失败，3回滚成功

    }
    print("___shisun_send_billog_________", data)
    player:billlog("third_game_order", data) 
end

--注册视讯会员
local function register_shisun()
    local user_data = player.user_data
    local uid = player.uid
    local user_data = player.user_data
    local shisun_platform = user_data.shisun_platform 
    print("_1__register_shisun__",uid, shisun_platform)
    if shisun_platform and shisun_platform ~= "" and shisun_platform == shisun_config.platform then 
        return true
    end 
    local data = {
        uid = uid,
        third_platform = shisun_config.platform,
    }
    local status, body = handler.common_post(constant.REGISTER_SHISUN_URL, cjson.encode(data), true)
    if not body or status ~= 200 then
        status = status or error_code.REMOTE_CALL_FAIL
        errlog("___register_shisun______",status, body)
        return false, status
    end
    local body = cjson.decode(body)
    print("_2__register_shisun__",uid, body.code)
    if body.code == 0 or body.code == 10100 then
        --记录
        player.user_data.shisun_platform = shisun_config.platform
        return true
    end        
    errlog("_3__register_shisun__",uid, body)    
    return false, body.code
end

--把金币转到视讯
local function set_shisun_coin(base_data)
    local uid = player.uid
    local user_data = player.user_data
    local platform = shisun_config.platform
    dbglog("______set_shisun_coin___1__", uid, platform) 

    local coins = base_data.coins
    local max_coins = server_config.shixun_coins_max or 200
    max_coins = max_coins*100 --分
    if coins > max_coins then --一次只能转入的最大值
        coins = max_coins 
    end
    dbglog("______set_shisun_coin___2__", coins)
    if coins <= 0 then 
        return true
    end    
    local ok, order_id = call_order_id(uid)
    if not ok then 
        errlog("___call_order_id__faild___", uid, order_id)
        return false
    end    
    --把金币转到视讯
    local rs = reason.SET_SHISUN_COIN
    local billInfo =  {
        table_type = shisun_config.game_type,
        game_type = shisun_config.game_code,
        client_version = player.client_version,
        channel = player.channel,
        cur_channel = player.cur_channel,
        device_id = player.device_id,
        device_brand = player.device_brand,        
    }        
    local ok, succ, ret = R().basesvr({key=uid}):call('.msg_handler', 'reduce_coins', uid, coins, rs, billInfo)
    if not ok or not succ then
        errlog(uid,'操作金币失败failed to reduce_coins', ok, succ, ret, rs)        
        return false, error_code.REMOTE_CALL_FAIL
    end 
    notify_money_changed(uid,{coins = ret.curr})


    local data = {
        uid = uid,
        amount = coins,
        third_platform = shisun_config.platform,
        order_id = ""..order_id,
    }
    dbglog("______set_shisun_coin___3__",data)
    local status, body = handler.common_post(constant.STE_SHISUN_COIN_URL, cjson.encode(data), true)
    if not body or status ~= 200 then
        errlog("_1___error___set_shisun_coin", status, body)  
        errlog("__1____视讯转入失败了,自动返还金币_",uid, coins)
        local ok = back_coin(coins)
        -- local msg = "调用web_proxy失败"
        -- local st = 3
        -- if ok then             
        --     msg = msg .. "(金币已自动返回到用户帐户)"
        -- else
        --     st = 2
        --     msg = msg .. "(金币已自动返回失败)"
        -- end
        -- send_billog(platform, uid, coins, 1, status, msg, order_id, st)          
        return false, status
    end    
    dbglog("______set_shisun_coin___4__", status, body)
    body = cjson.decode(body)
    if body.code ~= 0 then 
        errlog("_2___error___set_shisun_coin", status, body) 
        --后台已知错误
        if body.code ~= 30001 and body.code ~= 30002 then 
            errlog("__2____视讯转入失败了,自动返还金币_",uid, coins)
            local ok = back_coin(coins)
            -- local msg = body.msg or ""
            -- local st = 3
            -- if ok then 
            --     msg = msg .. "(金币已自动返回到用户帐户)"
            -- else
            --     st = 2
            --     msg = msg .. "(金币已自动返回失败)"
            -- end            
            -- send_billog(platform, uid, coins, 1, body.code, msg, order_id, st)      
            return false, body.code
        end

        --未知错误
        errlog("code__", body.code)
        errlog("______视讯转入失败了,要联系客户_",uid, coins)
        --给后台发billog
        send_billog(platform, uid, coins, 1, body.code, body.msg, order_id, 2)          
        return false, body.code
    end
    player.coins = base_data.coins - coins
    notify_money_changed(uid,{
        coins = player.coins,
    })    

    send_billog(platform, uid, coins, 1, 0, nil, order_id, 1)
    return true
end

--把金币从视讯转回来
local function get_shisun_coin(platform)
    if not platform then 
        return true
    end
    local user_data = player.user_data
    local uid = player.uid
    local shisun_table_type = user_data.shisun_table_type 

    local ok, order_id = call_order_id(uid)
    if not ok then 
        errlog("___call_order_id__faild___", uid, order_id)
        return true
    end    
    local data = {
        uid = uid,
        third_platform = platform,
        order_id = ""..order_id,
    }    
    dbglog("___1___get_shisun_coin__", data)
    --把金币从视讯转回来
    local status, body = handler.common_post(constant.GET_SHISUN_COIN_URL, cjson.encode(data), true)
    if not body or status ~= 200 then
        status = status or error_code.REMOTE_CALL_FAIL
        errlog("______get_shisun_coin__",status, body)
        local msg = "调用web_proxy失败"        
        send_billog(platform, uid, coins, 2, status, msg, order_id, 2)        
        return false, status
    end    
    dbglog("___2___get_shisun_coin__", body)
    local body = cjson.decode(body)    
    --更新用户金币
    local coins = body.result or 0
    if body.code ~= 0 then 
        errlog("______get_shisun_coin__", body)
        return false, body.code
    end
    coins = math.abs(coins)
    local game_type = 0
    local table_type = 0    
    if shisun_table_type then 
        game_type = math.floor(shisun_table_type / 100)
        table_type = shisun_table_type
    end
    if coins ~= 0 then 
        local reason = reason.GET_SHISUN_COIN
        local billInfo =  {
            table_type = table_type,
            game_type = game_type,
            client_version = player.client_version,
            channel = player.channel,
            cur_channel = player.cur_channel,
            device_id = player.device_id,
            device_brand = player.device_brand,        
        }        
        local ok, succ, ret = R().basesvr({key=uid}):call('.msg_handler', 'add_coins', uid, coins, reason, billInfo)
        if not ok or not succ then
            errlog(uid,'操作金币失败failed to add coins', ok, succ, coins, reason)     
            local msg = "basesvr add_coins失败__"        
            send_billog(platform, uid, coins, 2, 1, msg, order_id, 2)                 
            return false
        end  
        send_billog(platform, uid, coins, 2, 0, nil, order_id, 1)
        player.coins = ret.curr
        notify_money_changed(uid,{
            coins = player.coins,
        })
        
    end   
    --如果是从视讯里出来的，状态改为在大厅
    print("___1____shisun_table_type___",shisun_table_type)
    if shisun_table_type then 
        user_data.shisun_table_type = 0
        R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type=0})                
    end
        
         
    return true
end

--离开视讯时记录游戏房间输赢
local function shisunWinLose()
    local uid = player.uid
    local user_data = player.user_data
    local shisun_table_type = user_data.shisun_table_type
    print("____1___shisunWinLose___", uid, shisun_table_type)
    if not uid or shisun_table_type == 0 then --没有进入视讯游戏        
        return 
    end    
    user_data.shisun_table_type = 0 
    local shisun_config = getShisunConf(shisun_table_type)
    local table_type = shisun_config.game_type
    local game_type = shisun_config.game_code
    local game_name = shisun_config.game_name
    local enter_time = player.shisun_enter_time
    local enter_coins = player.shisun_enter_coins
    local enter_safe_coins = player.shisun_safe_coins
    local coins = player.coins
    local table_gid = enter_time .. "_" .. table_type .."_"..uid
    local ok, safe_coins = R().basesvr({key=uid}):call('.msg_handler','get_safe_box',uid)
    if not ok then 
        errlog("________取保险箱金币错误___", uid, table_type, enter_time)
    end
    local data = {
        table_gid = table_gid, --唯一标记
        table_type = table_type,
        name = game_name,        
        enter_coins = enter_coins, --进入时身上金币
        enter_safe_coins = enter_safe_coins, --进入时保险箱金币 
        enter_time = enter_time, --进入时间
        leave_time = os.time(), --离开时间
        leave_coins = coins, --离开时身上金币
        leave_safe_coins = safe_coins, --离开时保险箱金币
        win_lose = coins - enter_coins, --在玩游戏内产生的输赢
        free = 0, --玩游戏交上的台费
    }
    dbglog("_______user_leave_shisun_game_____",  data)
    player:billlog("user_leave_game", data)
end


--检查玩家的视讯游戏状态
local function check_shisun_state()
    if not player then 
        return 
    end
    local uid = player.uid
    local user_data = player.user_data
    local shisun_platform = user_data.shisun_platform --php会做绑定
    print("__1_check_shisun_state______",uid, shisun_platform)
    if not shisun_platform or shisun_platform == "" then 
        return
    end    

    local res = get_shisun_coin(shisun_platform)     
    if not res then 
        errlog("_____从视讯返回金币错误__", shisun_platform, uid)                  
    end    
    print("__3_check_shisun_state______",res)
    -- shisunWinLose()
end

------------------------------------------



------------------------------------------



------------------------------------------


--请求进入视讯游戏
function shisun_handler.REQ_ENTER_SHISUN(msg)
    print("_______REQ_ENTER_SHISUN_________", msg)
    if not msg then 
        return
    end
    if not can_set_shisun then 
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', {result=1})       
    end
    can_set_shisun = false
    skynet.timeout(200, function()
        can_set_shisun = true
    end)    
    --在别的游戏中时不可以进入视讯游戏
    local uid = player.uid
    local user_data = player.user_data
    local return_url = msg.return_url or "close"
    local game_type = msg.game_type --游戏id
    if not game_type then 
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', {result = error_code.RSP_FAIL})
    end

    local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
    if not ok or not base_data then 
        errlog(uid,'取base数据失败 get_base_data failed ')
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', {result = error_code.RSP_FAIL})
    end    

    local limit_num = 20*100
    print("_______REQ_ENTER_SHISUN____2_____",uid, base_data.coins, limit_num)
    if base_data.coins < limit_num then 
        local res = getErrResult(error_code.SHISUN_LIMIT, limit_num/100)
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', res)
    end    
    shisun_config = getShisunConf(game_type)
    if not shisun_config then 
        errlog("____取不到视讯配置__shisun_config___", msg)
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', {result = error_code.SHISUN_CONF_ERR})        
    end
    -- --游戏入口没开
    -- if shisun_config.status ~= 0 then 
    --     errlog("____game_status___", shisun_config.status)
    --     return send_to_gateway('shisun.RSP_ENTER_SHISUN', {result = error_code.RSP_FAIL})         
    -- end

    if not isInTableSvr(uid) then 
        return 
    end

    --注册会员
    local ok, code = register_shisun()
    print("_______REQ_ENTER_SHISUN____3_____")
    if not ok then 
        local res = getErrResult(error_code.SHISUN_REG_ERR, code)
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', res)                    
    end
    --用于登录时拉取一次
    -- player.third_platform = shisun_config.platform
    --进入游戏
    local data = {
        uid = uid,
        game_code = shisun_config.type_code,
        table_code = shisun_config.table_code,
        third_platform = shisun_config.platform,
        extra_params = {returnUrl = return_url},
    }
    print("_______REQ_ENTER_SHISUN____4_____", data)
    local status,body = handler.common_post(constant.ENTER_SHISUN_URL, cjson.encode(data), true)
    if not body or status ~= 200 then
        status = status or error_code.REMOTE_CALL_FAIL
        errlog("REQ_ENTER_SHISUN",status, body)
        local res = getErrResult(error_code.SHISUN_URL_ERR, status)
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', res)
    end
    local body = cjson.decode(body)
    if body.code ~= 0 then 
        errlog("REQ_ENTER_SHISUN",body)
        local res = getErrResult(error_code.SHISUN_URL_ERR, body.code)
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', res)
    end
    print("REQ_ENTER_SHISUN______5___", body)
    -- player.shisun_enter_time = os.time()
    -- player.shisun_enter_coins = player.coins
    -- player.shisun_safe_coins = R().basesvr({key=uid}):call('.msg_handler','get_safe_box',uid)
    --把金币转到视讯
    local ok, code = set_shisun_coin(base_data)
    print("_______REQ_ENTER_SHISUN____6_____", res)
    if not ok then 
        local res = getErrResult(error_code.SHISUN_SET_COIN_ERR, code)
        return send_to_gateway('shisun.RSP_ENTER_SHISUN', res)                    
    end
    user_data.shisun_table_type = shisun_config.game_type
    R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type = game_type, curr_table_type = game_type})
    local data = {        
        url = body.result
    }
    return send_to_gateway('shisun.RSP_ENTER_SHISUN', data)
end

--请求退出视讯游戏
function shisun_handler.REQ_LEAVE_SHISUN(msg)
    print("________REQ_LEAVE_SHISUN_______", msg)
    --
    local uid = player.uid
    local user_data = player.user_data    
    -- local shisun_table_type = user_data.shisun_table_type
    local shisun_platform = user_data.shisun_platform
    print("_________shisun_platform____", uid, shisun_platform)
    if not shisun_platform or shisun_platform == "" then 
        return send_to_gateway('shisun.RSP_LEAVE_SHISUN', {result=0})
    end  
    --把金币从视讯转回来
    local ok, code = get_shisun_coin(user_data.shisun_platform)
    if not ok then 
        local res = getErrResult(error_code.SHISUN_GET_COIN_ERR, code)
        return send_to_gateway('shisun.RSP_LEAVE_SHISUN', res)                    
    end    
    --玩家位置改为大厅
    notify_money_changed(uid,{
        coins = player.coins,
    })
    -- shisunWinLose() --写入流水
    local data = {
        result = 0,
    }
    return send_to_gateway('shisun.RSP_LEAVE_SHISUN', data)

end

--请求视讯游戏转回金币
function shisun_handler.REQ_GET_SHISUN_COIN(msg)
    if not can_get_shisun then 
        return send_to_gateway('shisun.RSP_GET_SHISUN_COIN', {result=1})       
    end
    can_get_shisun = false
    skynet.timeout(300, function()
        can_get_shisun = true
    end)
    local uid = player.uid
    local user_data = player.user_data
    local shisun_platform = user_data.shisun_platform
    print("_________shisun_platform____", uid, shisun_platform)
    if not shisun_platform or shisun_platform == "" then 
        return send_to_gateway('shisun.RSP_GET_SHISUN_COIN', {result=0})
    end    
    for _, platform in pairs(constant.SHISUN_PLATFORM_LIST) do 
        local res = get_shisun_coin(platform)
        if res then 
            dbglog("___1___REQ_GET_SHISUN_COIN___", uid, platform )            
        else
            errlog("___2___REQ_GET_SHISUN_COIN___", uid, platform )
        end
    end

    return send_to_gateway('shisun.RSP_GET_SHISUN_COIN', {result=0})
end

-- --请求视讯游戏试玩地址
-- function shisun_handler.REQ_TEST_SHISUN_URL(msg)
--     --
--     print("____111____REQ_TEST_SHISUN_URL_______", msg)
--     local uid = player.uid
--     local status,body = handler.common_post(constant.GET_SHISUN_COIN_URL,cjson.encode({}))
--     if not body or status ~= 200  then
--         errlog("REQ_TEST_SHISUN_URL",status, body)
--         return false
--     end   
--     local body = cjson.decode(body)
--     dbglog("__2_REQ_TEST_SHISUN_URL____", body) 
-- end























--------------------------------------------------------
-- handler.register_module_handlers_ex('hall', shisun_handler)
handler.register_module_handlers('shisun', shisun_handler)

local M = {
    check_shisun_state = check_shisun_state,
}

return M